package com.fuyun.rpc.common.serializer;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fuyun.rpc.common.domain.RpcRequest;
import com.fuyun.rpc.common.domain.RpcResponse;

import java.io.IOException;

/**
 * @author: zrq1351
 * @date: 2025/2/15
 */
public class JsonSerializer implements Serializer {
	private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

	@Override
	public <T> byte[] serialize(T obj) {
		try {
			return OBJECT_MAPPER.writeValueAsBytes(obj);
		} catch (JsonProcessingException e) {
			throw new RuntimeException(e);
		}
	}

	@Override
	public <T> T deserialize(byte[] bytes, Class<T> classType) {
		T obj;
		try {
			obj = OBJECT_MAPPER.readValue(bytes, classType);
			if (obj instanceof RpcRequest) {
				return handleRequest((RpcRequest)obj, classType);
			}
			if (obj instanceof RpcResponse) {
				return handleResponse((RpcResponse)obj, classType);
			}
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
		return obj;
	}

	/**
	 * 由于 Object 的原始对象会被擦除，导致反序列化时会被作为 LinkedHashMap 无法转换成原始对象，因此这里做了特殊处理
	 *
	 * @param rpcRequest rpc 请求
	 * @param type       类型
	 * @return {@link T}
	 * @throws IOException IO异常
	 */
	private <T> T handleRequest(RpcRequest rpcRequest, Class<T> type) throws IOException {
		Class<?>[] parameterTypes = rpcRequest.getParameterTypes();
		Object[] args = rpcRequest.getArgs();

		// 循环处理每个参数的类型
		for (int i = 0; i < parameterTypes.length; i++) {
			Class<?> clazz = parameterTypes[i];
			// 如果类型不同，则重新处理一下类型
			if (!clazz.isAssignableFrom(args[i].getClass())) {
				byte[] argBytes = OBJECT_MAPPER.writeValueAsBytes(args[i]);
				args[i] = OBJECT_MAPPER.readValue(argBytes, clazz);
			}
		}
		return type.cast(rpcRequest);
	}

	/**
	 * 由于 Object 的原始对象会被擦除，导致反序列化时会被作为 LinkedHashMap 无法转换成原始对象，因此这里做了特殊处理
	 *
	 * @param rpcResponse rpc 响应
	 * @param type        类型
	 * @return {@link T}
	 * @throws IOException IO异常
	 */
	private <T> T handleResponse(RpcResponse rpcResponse, Class<T> type) throws IOException {
		// 处理响应数据
		byte[] dataBytes = OBJECT_MAPPER.writeValueAsBytes(rpcResponse.getData());
		rpcResponse.setData(OBJECT_MAPPER.readValue(dataBytes, rpcResponse.getDataType()));
		return type.cast(rpcResponse);
	}
}